<template>
  <div class="preview-panel flex gap-3.5" style="height: 600px">
    <div class="bg-white border-rounded border-1 flex flex-col" style="width: 95px">
      <div
        class="cursor-pointer flex"
        style="height: 24px"
        @click="handleArrowUp"
        v-show="showArrowUp"
      >
        <el-icon style="margin: auto"><ArrowUp /></el-icon>
      </div>
      <div class="flex-1 overflow-hidden" ref="specScrollBox">
        <ul
          :style="specStyles"
          class="transition-all duration-300 pos-relative"
          ref="specListBox"
        >
          <li
            v-for="(item, index) in mediaList"
            :key="`preview-${index}`"
            class="p-1 text-center"
          >
            <div
              class="cursor-pointer border-rounded overflow-hidden border-1 boredr-gray-300 hover:border-red"
              @mouseenter="handleThumbnailClick(Number(index))"
              @click="hoverThumbnailClick(Number(index))"
              style="line-height: 0; width: 85px; height: 85px"
              :class="{ selected: selectedIndex === Number(index) }"
            >
              <el-image :src="item.thumbnail" fit="fill" />
              <div
                v-if="item.type === 'video'"
                class="pos-absolute border-rounded-full bg-gray-300"
                style="top: 50%; left: 50%; transform: translate(-50%, -50%)"
              >
                <el-icon size="25"><CaretRight /></el-icon>
              </div>
            </div>
          </li>
        </ul>
      </div>
      <div
        class="cursor-pointer flex"
        style="height: 24px"
        @click="handleArrowDown"
        v-show="showArrowDown"
      >
        <el-icon style="margin: auto"><ArrowDown /></el-icon>
      </div>
    </div>
    <div class="flex-1">
      <div
        class="preview-box bg-white pos-relative"
        @mousemove="handleMouseMove"
        @mouseleave="handleMouseLeave"
        ref="previewBoxRef"
      >
        <div class="preview-img border-rounded-xl border-1 overflow-hidden w-full h-full">
          <template v-if="selectedMedia">
            <template v-if="selectedMedia?.type === 'video'">
              <video
                :src="selectedMedia.videoSrc"
                :poster="selectedMedia.poster"
                class="w-full h-full object-cover"
                style="max-height: 600px"
                autoplay
                controls
                muted ="true"
              ></video>
            </template>
            <template v-else-if="selectedMedia.type === 'image'">
              <el-image :src="selectedMedia.src" fit="fill"
            /></template>
          </template>
        </div>
        <div
          class="zoom-mask pos-absolute border-rounded-xl hover:cursor-move"
          v-show="showZoomMask && canShowZoom"
          ref="zoomMaskRef"
          :style="{ left: mouseX + 'px', top: mouseY + 'px' }"
        ></div>
        <!-- 放大镜 -->
        <Transition name="fade" mode="default">
          <div
            class="zoom-box border-rounded-xl" style="z-index: 999;"
            v-if="showZoomBox && canShowZoom"
            :style="zoomImageStyle"
          ></div
        ></Transition>
      </div>
    </div>
  </div>
</template>
<script lang="ts" setup>
import { ref, computed, onMounted, watch, nextTick } from "vue";
import type { PropType } from "vue";
import type { MediaItem, MediaType } from "@/types/media.ts";
import { ArrowUp, ArrowDown, CaretRight } from "@element-plus/icons-vue";

/**
 * 待解决问题：
 * 1、少量图的显示问题，
 * 2、自适应问题
 */
const props = defineProps({
  mediaList: {
    type: Array as PropType<MediaItem[]>,
    default: () => [],
  },
});
console.log("mediaList: ", props.mediaList);
const SCROLL_OFFSET = 565;
const Scale = 2;
const ARROW_HEIGHT = 24; // 上下箭头的高度，用于精确计算可滚动区域

const specScrollBox = ref<HTMLDivElement | null>(null);
const boxHeight = ref(0);
const specListBox = ref<HTMLDivElement | null>(null);
const specListBoxHeight = ref(0);
const translateY = ref(0);

// 新增: 当前选中的图片，用于主图预览
const selectedIndex = ref<number>(0);
const selectedMedia = computed<MediaItem>(() => props.mediaList[selectedIndex.value]);

// 修改: 只有图片才显示放大镜
const canShowZoom = computed(() => selectedMedia.value.type === "image");

// 1. 定义最大和最小的 translateY 值
//    这些值应该在高度变化时重新计算，所以我们用 computed 来定义它们
const minTranslateY = computed(() => {
 // 最小值（滚动到最底部）
  // 可滚动区域高度 = 父容器高度 - 两个箭头的高度
  const scrollableHeight = boxHeight.value - 2 * ARROW_HEIGHT;
  if (scrollableHeight <= 0 || specListBoxHeight.value <= scrollableHeight) {
    return 0; // 如果列表高度不足以滚动，则无需偏移
  }
  return -(specListBoxHeight.value - scrollableHeight);

});

const maxTranslateY = computed(() => {
  // 最大值（滚动到最顶部），列表不能向下滚出父容器
  return 0;
});
// 明确滚动方向为向下滚动
const handleArrowUp = () => {
  // 计算目标位置：当前位置 + 一个步长
  const targetY = translateY.value + SCROLL_OFFSET;

  // 使用 Math.min 确保目标位置不会超过最大值（即 0）
  // 如果 targetY 是 100，Math.min(100, 0) 会得到 0
  // 如果 targetY 是 -50，Math.min(-50, 0) 会得到 -50
  translateY.value = Math.min(targetY, maxTranslateY.value);
};
//
const handleArrowDown = () => {
  // 计算目标位置：当前位置 - 一个步长
  const targetY = translateY.value - SCROLL_OFFSET;

  // 使用 Math.max 确保目标位置不会小于最小值
  // 如果 targetY 是 -200，Math.min(-200, -93) 会得到 -93
  // 如果 targetY 是 -50，Math.min(-50, -93) 会得到 -50
  translateY.value = Math.max(targetY, minTranslateY.value);
};

// 新增: 处理缩略图点击
const handleThumbnailClick = (index: number) => {
  selectedIndex.value = index;
};
// 新增: 处理缩略图点击
const hoverThumbnailClick = (index: number) => {
  if (index === -1) {
    selectedIndex.value = -1;
    return;
  }
  selectedIndex.value = index;
  // 可选: 点击后自动滚动到该缩略图的位置
  // (这里需要更复杂的逻辑来计算目标位置，暂时省略)
};
const showArrowUp = computed(() => {
  return translateY.value < maxTranslateY.value;
});
const showArrowDown = computed(() => {
 return translateY.value > minTranslateY.value;
});
const specStyles = computed(() => {
  return {
    transform: `translateY(${translateY.value}px)`,
  };
});
// 封装高度计算逻辑，避免重复代码
const calculateHeights = () => {
  if (specScrollBox.value) {
    boxHeight.value = specScrollBox.value.offsetHeight;
  }
  if (specListBox.value) {
    specListBoxHeight.value = specListBox.value.offsetHeight;
  }
  // 每次高度变化后，重置滚动位置，避免错位
  translateY.value = 0;
};

// ---放大镜模块---
const previewBoxRef = ref<HTMLDivElement | null>(null);
const zoomMaskRef = ref<HTMLDivElement | null>(null);
const mouseX = ref(0); // 鼠标X坐标（相对于缩略图）
const mouseY = ref(0); // 鼠标Y坐标（相对于缩略图）
const showZoomMask = ref(false);
const showZoomBox = ref(false);
let animationFrameId: number | null = null;

// 鼠标移动处理函数：更新位置
const handleMouseMove = (event: MouseEvent) => {
  if (!canShowZoom.value) return; // 只有图片才能放大

  if (animationFrameId) {
    cancelAnimationFrame(animationFrameId); // 取消之前的动画帧
  }

  animationFrameId = requestAnimationFrame(() => {
    showZoomMask.value = true;
    if (!previewBoxRef.value || !zoomMaskRef.value) return;
    const parentRect = previewBoxRef.value.getBoundingClientRect();
    const maskRect = zoomMaskRef.value.getBoundingClientRect();

    const parentLeft = parentRect.left;
    const parentTop = parentRect.top;

    const mouseXValue = event.clientX - parentLeft;
    const mouseYValue = event.clientY - parentTop;

    const maxX = parentRect.width - maskRect.width;
    const maxY = parentRect.height - maskRect.height;

    mouseX.value = Math.max(0, Math.min(mouseXValue - maskRect.width / 2, maxX));
    mouseY.value = Math.max(0, Math.min(mouseYValue - maskRect.height / 2, maxY));

    showZoomBox.value =
      mouseXValue >= 0 &&
      mouseXValue <= parentRect.width &&
      mouseYValue >= 0 &&
      mouseYValue <= parentRect.height;
  });
};

const handleMouseLeave = () => {
  if (animationFrameId) {
    cancelAnimationFrame(animationFrameId);
    animationFrameId = null; // 取消后，将 id 置为 null，是个好习惯
  }
  showZoomBox.value = false;
  showZoomMask.value = false;
};

// 放大图样式：根据鼠标位置计算背景位置
const zoomImageStyle = computed(() => {
  if (!previewBoxRef.value|| !selectedMedia.value?.src) return;
  const imgWidth = previewBoxRef.value.offsetWidth;
  const imgHeight = previewBoxRef.value.offsetHeight;
  // 计算鼠标在预览图上的相对位置 (0 到 1)
  const ratioX = mouseX.value / imgWidth;
  const ratioY = mouseY.value / imgHeight;

  // 背景位置应该直接使用这个相对位置的百分比
  // 这样图片的 (ratioX * 100%) 点与容器的 (ratioX * 100%) 点对齐
  const bgPosX = ratioX * 100;
  const bgPosY = ratioY * 100;

  return {
    backgroundImage: `url(${selectedMedia.value.src})`,
    backgroundPosition: `${bgPosX}% ${bgPosY}%`,
    backgroundSize: `${imgWidth * Scale}px ${imgHeight * Scale}px`,
  };
});

// 增强: 监听 images 的变化，动态重新计算高度
// 这对于异步加载图片或图片数量会变化的场景非常重要
watch(
  () => props.mediaList,
  () => {
    // 使用 nextTick 确保 DOM 更新完成后再计算高度
    nextTick(calculateHeights);
  },
  { deep: true, immediate: true } // immediate: true 确保在 onMounted 之前也执行一次
);

onMounted(() => {
  calculateHeights();
});
</script>
<style lang="scss" scoped>
.selected {
  border: 1px solid red;
}
.preview-box {
  .zoom-mask {
    width: 186px;
    height: 186px;
    background-color: #ffffff79;
  }
  .zoom-box {
    width: 600px;
    height: 600px;z-index: 209;
    background-color: #cc1515;
    position: absolute;
    top: 0;
    left: calc(100% + 15px);
    background-image: url("https://img10.360buyimg.com//n0/jfs/t1/302408/22/14708/45779/684f6d14Fbbaba9c9/d3efc425c5bd5592.jpg.avif");
    background-repeat: no-repeat;
  }
}
</style>
